#include "Image.h"
#include <Windows.h>
#include <algorithm>
#include <math.h>
#include <iostream>

Image::Image():Matrix() {} //构造函数，创建行列都为零的Image对象
Image::Image(int h, int w):Matrix(h,w){} //构造函数重载，创建h行，w列的Image对象
Image::Image(int h, int w, Pixel pix):Matrix(h,w,pix){} //构造函数重载，创建的图像像素值都为val;
Image::Image(const char* ImageName):Matrix() //构造函数重载，利用文件名从硬盘加载图像文件成为Image对象;
{
    ReadBMP(ImageName);
}
Image::Image(const Matrix &m):Matrix(m) {} //构造函数重载，由Matrix类对象构造Image类对象
Image::Image(const Image &im):Matrix(im) //拷贝构造函数;
{

}
Image::~Image()
{
    delete[] dataI;
} //析构函数;

int Image::ReadBMP(const char* ImageName) //从硬盘文件中读入图像数据;
{
    FILE *fp = nullptr;
    fp = fopen(ImageName,"rb");
    if(!fp) //文件打开失败
    {
        printf("Read error");
        return 1;
    }
    BITMAPFILEHEADER fileHead;
    BITMAPINFOHEADER infHead;
    fread(&fileHead,sizeof(BITMAPFILEHEADER),1,fp);
    fread(&infHead,sizeof(BITMAPINFOHEADER),1,fp);
    if(24 != infHead.biBitCount)//文件格式不符
    {
        printf("Image error");
        return 2;
    }
    long w = infHead.biWidth, h = infHead.biHeight;
    if(w % 4)
    {
        w = (((w * 24 / 8 + 3 ) ) / 4 * 4 ) / 3;
    }
    Zeros(h,w);
    unsigned char temp[3] = {0};
    for(int i = 0;i < h;i++)
    {
        for(int j = 0;j < w;j++)
        {
            fread(temp, 3, 1, fp);
            At(i,j).red = temp[0];
            At(i,j).gre = temp[1];
            At(i,j).blu = temp[2];
        }
    }
    fclose(fp);
    return 0;
}
int Image::WriteBMP(const char* filename) //将图像数据保存为图像文件;
{
    FILE *fp;
    fp = fopen(filename,"wb");
    if(!fp)//文件打开失败
    {
        return 1;
    }
    BITMAPFILEHEADER fileHead;
    BITMAPINFOHEADER infHead;
    infHead.biHeight = Height();
    infHead.biWidth = Width();
    fileHead.bfType = 0x4d42;
    fileHead.bfOffBits = 54;
    infHead.biSize = 40;
    infHead.biPlanes = 1;
    infHead.biBitCount = 24;
    infHead.biCompression = 0;
    fwrite(&fileHead,sizeof(BITMAPFILEHEADER),1,fp);
    fwrite(&infHead,sizeof(BITMAPINFOHEADER),1,fp);
    int height = Height(), width = Width();
    for(int i = 0 ; i < height ; i++)
    {
        for(int j = 0;j < width;j++)
        {

            fwrite(&At(i ,j).red,1,1,fp);
            fwrite(&At(i ,j).gre,1,1,fp);
            fwrite(&At(i ,j).blu,1,1,fp);

        }
    }
    fclose(fp);
    return 0;
}

void Image::Flip(int code) //图像的翻转; code为0左右，1 上下;
{
    int height = Height(), width = Width();
    Image temp((*this));
    if(code)
    {
        for(int i = 0;i < height;i++)
        {
            for(int j = 0;j < width;j++)
            {
                At(i,j) = temp.At(height - i - 1,j);
            }
        }
    }
    else
    {
        for(int i = 0;i < height;i++)
        {
            for(int j = 0;j < width;j++)
            {
                At(i,j) = temp.At(i,width - j - 1);
            }
        }
    }
}

void Image::Resize(int h, int w) //图像的缩放为参数指定的大小
{

    if(w % 4)
    {
        w = (((w * 24 / 8 + 3 ) ) / 4 * 4 ) / 3;
    }
    Image temp(h, w);
    int th = Height(), tw = Width();
    double sizeH = double(th) / h;
    double sizeW = double(tw) / w;
    for(int i = 0;i < h;i++)
    {
        for(int j = 0;j < w;j++)
        {
            temp.At(i ,j) = At((i * sizeH), (j * sizeW));
        }
    }
    temp.CopyTo(*this);
}

int Image::Cut(int x1,int y1,int x2,int y2)//裁剪点(x1,y1)到点(x2,y2)的图像
{
    if(x1 == x2 || y1 == y2 || x1 < 0 || x2 < 0 || y1 < 0 || y2 < 0 )
    {
        printf("input error");//输入值不合理
        return 1;
    }
    if(x1 > x2)
    {
        int temp = x1;
        x1 = x2;
        x2 = temp;
        temp = y1;
        y1 = y2;
        y2 = temp;
    }
    if(x2 > Width() || y2 > Height())//输入值超过图像大小
    {
        if(x2 > Width())
        {
            x2 = Width();
        }
        if(y2 > Height())
        {
            y2 = Height();
        }
    }
    long w = x2 - x1, h = y2 - y1;
    if(w % 4)
    {
        w = (((w * 24 / 8 + 3 ) ) / 4 * 4 ) / 3;
    }
    Image temp(h,w);
    for(int i = 0;i < y2 - y1;i++)
    {
        for(int j = 0;j < x2 - x1;j++)
        {
            temp.At(i,j) = At(y1 + i,x1 + j);
        }
    }
    temp.CopyTo((*this));
    return 0;
}
int Image::Rotate(int degree)//图像旋转的函数（旋转角度为90度的整数倍）
{
    int height = Height(), width = Width();
    if(0 == degree || 360 == degree || -360 == degree)
    {}
    else if(180 == degree || -180 == degree)
    {
        (*this).Flip(1);
    }
    else if(90 == degree || -270 == degree)
    {
        Image temp(width,height);
        for(int i = 0;i < height;i++)
        {
            for(int j = 0;j < width;j++)
            {
                temp.At(width - j-1, i) = At(i, j); //顺时针旋转
                // temp.data[width - j-1][height - i - 1] = data[i][j];//逆时针旋转
            }
        }
        (*this) = temp;
    }
    else if(270 == degree || -90 == degree)
    {
        (*this).Rotate(90);
        (*this).Flip(0);
    }
    else
    {
        printf("value error");//输入值不合要求
        return 1;
    }
    return 0;
}

Image& Image::operator++()
{
    Matrix::operator++();
    return *this;
}

Image Image::operator++(int)
{
    Image temp(*this);
    Matrix::operator++();
    return temp;
}

Image& Image::operator--()
{

    Matrix::operator--();

    return *this;
}

Image Image::operator--(int)
{

    Image temp(*this);
    Matrix::operator--();

    return temp;
}

unsigned char * Image::getData()
{
    if(nullptr != dataI)
    {
        delete[] dataI;
    }
    int height = Height(), width = Width();
    dataI = new unsigned char[height * width * sizeof(Pixel)];
    unsigned char * temp = dataI;
    for(int i = 0; i < height ; i++)
    {
        for(int j = 0 ; j < width ; j++)
        {
            *temp++ = At(i,j).red;
            *temp++ = At(i,j).gre;
            *temp++ = At(i,j).blu;
        }
    }
    return dataI;
}

unsigned char & Image::getChannel(int height , int width , int color)
{
    switch (color)
    {
        case RED: return At(height, width).red;
        case GREEN: return At(height, width).gre;
        case BLUE: return At(height, width).blu;
    }
    return At(0,0).red;
}

void Image::setChannel(int height , int width , int color, unsigned char cha)
{
    switch (color)
    {
        case RED: At(height, width).red = cha; return;
        case GREEN: At(height, width).gre = cha; return;
        case BLUE: At(height, width).blu = cha; return;
    }

}

Image& Image::operator=(const Image & img)
{
    Matrix::operator=(img);
    return (*this);
}

//去雾
struct DarkCha
{
    unsigned char val;
    int height;
    int width;
};

bool compare(const DarkCha & f ,const DarkCha & b)
{
    return f.val > b.val;
}

int Image::remHaze(int minwinSize ,int tranwinSize, double tran, double w)
{
    int height = Height(), width = Width();
    Image dark(*this);
    for(int i = 0; i < height ; i++)
    {
        for(int j = 0; j < width; j++)
        {
            unsigned char minCha = 255;
            for(int z = 0 ; z < 3 ; z++)
            {
                if(dark.getChannel(i,j,z) < minCha)
                {
                    minCha = dark.getChannel(i,j,z);
                }
                for(int z = 0 ; z < 3 ; z++)
                {
                    dark.getChannel(i,j,z) = minCha;
                }
            }
        }
    }
    dark.minFilter(minwinSize);

    DarkCha* sortA = new DarkCha[(height + 1) * (width + 1)];//delete

    for(int i = 0;i < height;i++)
    {
        for(int j = 0;j < width;j++)
        {

            sortA[(i * width) + j].val = dark.At(i , j).red;
            sortA[(i * width) + j].height = i;
            sortA[(i * width) + j].width = j;

        }
    }
    std::sort(sortA , &sortA[(height + 1) * (width + 1)] , compare);
    int numA = double(height + 1) * double(width + 1) * 0.001;
    DarkCha A[numA];
    for(int i = 0 ; i < numA ; i++)
    {
        A[i] = sortA[i];
    }
    delete[] sortA;
    unsigned char maxRGB[3] = {0,0,0};
    for(int i = 0 ; i < numA ; i++)
    {
        if(At(A[i].height , A[i].width).red > maxRGB[0])
        {
            maxRGB[0] = At(A[i].height , A[i].width).red;
        }
        if(At(A[i].height , A[i].width).gre > maxRGB[1])
        {
            maxRGB[1] = At(A[i].height , A[i].width).gre;
        }
        if(At(A[i].height , A[i].width).blu > maxRGB[2])
        {
            maxRGB[2] = At(A[i].height , A[i].width).blu;
        }


    }

    dark = (*this);
    double minTtemp = 255;
    double T = tran;
    for(int i = 0;i < height;i++)
    {
        for(int j = 0;j < width;j++)
        {
            for(int si = i - tranwinSize;si < i + tranwinSize;si++)
            {
                if(si < 0 || si >= height)
                {
                    continue;
                }
                for(int sw = j - tranwinSize;sw < j + tranwinSize;sw++)
                {
                    if(sw < 0 || sw >= width)
                    {
                        continue;
                    }
                    for(int z = 0 ; z < 3 ; z++)
                    {
                        if(minTtemp > double(dark.getChannel(si,sw,z)) / double(maxRGB[z]))
                        {
                            minTtemp = double(dark.getChannel(si,sw,z)) / double(maxRGB[z]);
                        }
                    }
                }
            }
            if(T < (1 - w * minTtemp))
            {
                T = 1 - w * minTtemp;
            }
            for(int z = 0 ; z < 3 ; z++)
            {
                getChannel(i,j,z) =((getChannel(i,j,z) - maxRGB[z]) / T) + maxRGB[z];
            }
            minTtemp = 255;
            T = tran;
        }
    }

    return 0;
}

void Image::minFilter(int winSize)
{
    int height = Height(), width = Width();
    Image temp = (*this);
    unsigned char min[3] = {255,255,255};
    for(int i = 0;i < height;i++)
    {
        for(int j = 0;j < width;j++)
        {
            for(int si = i - winSize;si < i + winSize;si++)
            {
                if(si < 0 || si >= height)
                {
                    continue;
                }
                for(int sw = j - winSize;sw < j + winSize;sw++)
                {
                    if(sw < 0 || sw >= width)
                    {
                        continue;
                    }
                    if(temp.At(si,sw).red < min[0])
                    {
                        min[0] = temp.At(si , sw).red;
                    }
                    if(temp.At(si,sw).gre < min[1])
                    {
                        min[1] = temp.At(si , sw).gre;
                    }
                    if(temp.At(si,sw).blu < min[2])
                    {
                        min[2] = temp.At(si , sw).blu;
                    }
                }
            }
            At(i , j).red = min[0];
            At(i , j).gre = min[1];
            At(i , j).blu = min[2];
            min[0] = min[1] = min[2] = 255;
        }
    }
}

void Image::brightAdj(double mul)
{
    double temp;
    int height = Height(), width = Width();
    int col;
    for(int i = 0 ; i < height ; i++)
    {
        for(int j = 0 ; j < width ; j++)
        {
            // (col = At(i , j).red * (1 + (mul * ((255 - At(i , j).red) / 255.0)))) > 255 ? At(i , j).red = 255 : At(i , j).red = col;
            // (col = At(i , j).gre * (1 + (mul * ((255 - At(i , j).gre) / 255.0)))) > 255 ? At(i , j).gre = 255 : At(i , j).gre = col;
            // (col = At(i , j).blu * (1 + (mul * ((255 - At(i , j).blu) / 255.0)))) > 255 ? At(i , j).blu = 255 : At(i , j).blu = col;

            temp = ((765.0 - (At(i , j).red + At(i , j).gre + At(i , j).blu)) / 765.0) * mul;
            (col = At(i , j).red * (temp + 1)) > 255 ? At(i , j).red = 255 : At(i , j).red = col;
            (col = At(i , j).gre * (temp + 1)) > 255 ? At(i , j).gre = 255 : At(i , j).gre = col;
            (col = At(i , j).blu * (temp + 1)) > 255 ? At(i , j).blu = 255 : At(i , j).blu = col;
        }
    }
}

double max(double a , double b)
{
    if(a > b)
    {
        return a;
    }
    return b;
}

double min(double a , double b)

{
    if(a < b)
    {
        return a;
    }
    return b;
}

//灰度化
void Image::gray() {
    // 根据传进来的image 定义一个新的图片对象
    MyQImage newImage = Image(Height(), Width());
    // 对newImage所有点进行rgb的取出->求均值->重置操作
    for (int y = 0; y < newImage.height(); y++) {
        for (int x = 0; x < newImage.width(); x++) {

            //返回x,y点处结构体oldColor
            Pixel &oldColor = At(y, x);
            // 取该点结构体的r g b
            unsigned char average = (oldColor.gre + oldColor.blu + oldColor.red) / 3;
            // 重置x,y点的rgb值
            newImage.setPixel(y, x, average, average, average);
        }
    }
    newImage.CopyTo((*this));
}

int qBound(int low, int val, int high) {
    if (val > high)
        return high;
    else if (val < low)
        return low;
    return val;
}

// 伽马变换
void Image::gamma() {
    double k = 1.2;
    int height = Height();
    int width = Width();
    for (int i = 0; i < width; i++) {
        for (int j = 0; j < height; j++) {
            Pixel &color = At(j, i);
            double r = color.red;
            double g = color.gre;
            double b = color.blu;
            unsigned char R = qBound(0, (int) pow(r, k), 255);
            unsigned char G = qBound(0, (int) pow(g, k), 255);
            unsigned char B = qBound(0, (int) pow(b, k), 255);
            At(j, i) = {R, G, B};
        }
    }
}

void Image::fix(int sizeKernel) {
    int w = Width();
    int h = Height();
    for (int x = 0; x < sizeKernel / 2 + 1; x++) {
        for (int y = 0; y < h; y++) {
            setPixel(y, x, At(y, x + sizeKernel / 2 + 1));
        }
    }
    for (int x = w; x > w - sizeKernel / 2 - 1; x--) {
        for (int y = 0; y < Height(); y++) {
            setPixel(y, x, At(y, x - sizeKernel / 2 - 1));
        }
    }
    for (int x = 0; x < w; x++) {
        for (int y = 0; y < sizeKernel / 2 + 1; y++) {
            setPixel(y, x, At(y + sizeKernel / 2 + 1, x));
        }
    }
    for (int x = 0; x < w; x++) {
        for (int y = h; y > h - sizeKernel / 2 - 1; y--) {
            setPixel(y - 1, x, At(y - sizeKernel / 2 - 1, x));
        }
    }
}

//均值滤波
void Image::mean_filter() {
    //类似“卷积核” 权重都是1
    // 这里直接定义大小为3*3 不需要用户输入
    int kernel[3][3] = {
            {1, 1, 1},
            {1, 1, 1},
            {1, 1, 1}};
    int sizeKernel = 3;
    int sumKernel = 9;
    // 类似valid有效卷积 3*3核不超过图片
    for (int x = sizeKernel / 2; x < Width() - sizeKernel / 2; x++) {
        for (int y = sizeKernel / 2; y < Height() - sizeKernel / 2; y++) {
            int r = 0;
            int g = 0;
            int b = 0;
            // 在“卷积核”3*3区域进行r、g、b累加计算
            for (int i = -sizeKernel / 2; i <= sizeKernel / 2; i++) {
                for (int j = -sizeKernel / 2; j <= sizeKernel / 2; j++) {
                    Pixel &color = At(y + j, x + i);
                    r += color.red * kernel[sizeKernel / 2 + i][sizeKernel / 2 + j];
                    g += color.gre * kernel[sizeKernel / 2 + i][sizeKernel / 2 + j];
                    b += color.blu * kernel[sizeKernel / 2 + i][sizeKernel / 2 + j];
                }
            }
            // 除以以sumKernel求均值 要求不超过0-255 超了就赋值0/255
            r = qBound(0, r / sumKernel, 255);
            g = qBound(0, g / sumKernel, 255);
            b = qBound(0, b / sumKernel, 255);
            setPixel(y, x, r, g, b);
        }
    }
    fix(sizeKernel);
}

//高斯滤波
void Image::Gaussian_filter(int flage) {
    // 这里直接定义大小为3*3 不需要用户输入
    float kernel[3][3] = {
            {0.0625, 0.125, 0.0625},
            {0.125,  0.25,  0.125},
            {0.0625, 0.125, 0.0625}};
    int sizeKernel = 3;
    int sumKernel = 1; // 上面其实已经进行归一化了 不然这里是16

    for (int x = sizeKernel / 2; x < Width() - sizeKernel / 2; x++) {
        for (int y = sizeKernel / 2; y < Height() - sizeKernel / 2; y++) {
            int r = 0;
            int g = 0;
            int b = 0;
            for (int i = -sizeKernel / 2; i <= sizeKernel / 2; i++) {
                for (int j = -sizeKernel / 2; j <= sizeKernel / 2; j++) {
                    Pixel &color = At(y + j, x + i);
                    r += color.red * kernel[sizeKernel / 2 + i][sizeKernel / 2 + j];
                    g += color.gre * kernel[sizeKernel / 2 + i][sizeKernel / 2 + j];
                    b += color.blu * kernel[sizeKernel / 2 + i][sizeKernel / 2 + j];
                }
            }
            r = qBound(0, r / sumKernel, 255);
            g = qBound(0, g / sumKernel, 255);
            b = qBound(0, b / sumKernel, 255);

            // 如果是高斯变换
            if (flage && At(y, x).red + At(y, x).gre + At(y, x).blu == 0) {
                setPixel(y, x, 2.25 * r, 2.25 * g, 2.25 * b);
            } else { // 如果不是
                setPixel(y, x, r, g, b);
            }
        }
    }
    fix(sizeKernel);
}

// 快排
void myquick_sort(int s[], int l, int r) {
    if (l < r) {
        int i = l, j = r, x = s[l];
        while (i < j) {
            while (i < j && s[j] >= x)
                j--;
            if (i < j)
                s[i++] = s[j];

            while (i < j && s[i] < x)
                i++;
            if (i < j)
                s[j--] = s[i];
        }
        s[i] = x;
        myquick_sort(s, l, i - 1);
        myquick_sort(s, i + 1, r);
    }
}

//中值滤波
void Image::mid_value_filter() {
    int sizeKernel = 5;
    for (int x = sizeKernel / 2; x < Width() - sizeKernel / 2; x++) {
        for (int y = sizeKernel / 2; y < Height() - sizeKernel / 2; y++) {
            int midR = 0;
            int midG = 0;
            int midB = 0;
            int count = 0;
            int lstR[25] = {0};
            int lstG[25] = {0};
            int lstB[25] = {0};
            for (int i = -sizeKernel / 2; i <= sizeKernel / 2; i++) {
                for (int j = -sizeKernel / 2; j <= sizeKernel / 2; j++) {
                    lstR[count] = At(y + j, x + i).red;
                    lstG[count] = At(y + j, x + i).gre;
                    lstB[count] = At(y + j, x + i).blu;
                    //cout<<count<<endl;
                    count++;
                }
            }
            myquick_sort(lstR, 0, 24);
            myquick_sort(lstG, 0, 24);
            myquick_sort(lstB, 0, 24);
            midR = lstR[12];
            midG = lstG[12];
            midB = lstB[12];
            setPixel(y, x, midR, midG, midB);
        }
    }
    fix(sizeKernel);
};

//高斯金字塔——>缩小
void Image::lower() {
// 这里直接定义大小为3*3 不需要用户输入
    Gaussian_filter();
    Image new_im = Image(Height() / 2, Width() / 2);
    int countx = 0;
    int county = 0;
    for (int x = 0; x < Width() - 1; x++) {
        if (x % 2 != 0)
            continue;
        for (int y = 0; y < Height() - 1; y++) {
            if (y % 2 != 0)
                continue;
            Pixel &color = At(y, x);
            new_im.setPixel(county, countx, color);
            county++;
        }
        countx++;
        county = 0;
    }
    new_im.CopyTo((*this));
}

//高斯金字塔——>放大
void Image::upper() {
// 这里直接定义大小为3*3 不需要用户输入
    Image new_im = Image(Height() * 2, Width() * 2);
    int countx = 0;
    int county = 0;
    for (int x = 0; x < new_im.width(); x++) {
        if (x % 2 != 0)
            countx++;
        for (int y = 0; y < new_im.height(); y++) {
            if (x % 2 != 0 || y % 2 != 0) {
                Pixel color = {0, 0, 0};
                new_im.setPixel(y, x, color);
            } else {
                Pixel color = At(county, countx);
                new_im.setPixel(y, x, color);
            }
            if (y % 2 != 0)
                county++;
        }
        county = 0;
    }
    new_im.CopyTo((*this));
    Gaussian_filter(1);
}


// (单)阈值处理
void Image::threshold(int thresh, int maxval, int type) {
    gray();
    if (type == 0) {
        for (int y = 0; y < Height(); y++) {
            for (int x = 0; x < Width(); x++) {
                //返回x,y点处结构体oldColor
                Pixel &oldColor = At(y, x);
                // 取该点结构体的r g b
                if (oldColor.red > thresh) {
                    setPixel(y, x, maxval, maxval, maxval);
                } else {
                    setPixel(y, x, 0, 0, 0);
                }
            }
        }
    } else if (type == 1) {
        for (int y = 0; y < Height(); y++) {
            for (int x = 0; x < Width(); x++) {
                //返回x,y点处结构体oldColor
                Pixel &oldColor = At(y, x);
                // 取该点结构体的r g b
                if (oldColor.red > thresh) {
                    setPixel(y, x, 0, 0, 0);
                } else {
                    setPixel(y, x, maxval, maxval, maxval);
                }
            }
        }
    } else if (type == 2) {
        for (int y = 0; y < Height(); y++) {
            for (int x = 0; x < Width(); x++) {
                //返回x,y点处结构体oldColor
                Pixel &oldColor = At(y, x);
                // 取该点结构体的r g b
                if (oldColor.red > thresh) {
                    setPixel(y, x, thresh, thresh, thresh);
                }
            }
        }
    } else if (type == 3) {
        for (int y = 0; y < Height(); y++) {
            for (int x = 0; x < Width(); x++) {
                //返回x,y点处结构体oldColor
                Pixel &oldColor = At(y, x);
                // 取该点结构体的r g b
                if (oldColor.red <= thresh) {
                    setPixel(y, x, 0, 0, 0);
                }
            }
        }
    } else if (type == 4) {
        for (int y = 0; y < Height(); y++) {
            for (int x = 0; x < Width(); x++) {
                //返回x,y点处结构体oldColor
                Pixel &oldColor = At(y, x);
                // 取该点结构体的r g b
                if (oldColor.red > thresh) {
                    setPixel(y, x, 0, 0, 0);
                }
            }
        }
    } else if (type == 5) { //这个是为后面双阈值处理准备的
        for (int y = 0; y < Height(); y++) {
            for (int x = 0; x < Width(); x++) {
                //返回x,y点处结构体oldColor
                Pixel &oldColor = At(y, x);
                // 取该点结构体的r g b
                if (oldColor.red > thresh) {
                    setPixel(y, x, 0, 0, 0);
                }
            }
        }
    }

}

// 梯度计算
void Image::Sobel() {
    gray();
    Gaussian_filter();
    // x y 方向上的核
    int Gx[3][3] = {{-1, 0, 1},
                    {-2, 0, 2},
                    {-1, 0, 1}};
    int Gy[3][3] = {{-1, -2, -1},
                    {0,  0,  0},
                    {1,  2,  1}};
    int sizeKernel = 3;
    Image new_im = Image(Height(), Width());
    // 类似valid有效卷积 3*3核不超过图片
    for (int x = sizeKernel / 2; x < Width() - sizeKernel / 2; x++) {
        for (int y = sizeKernel / 2; y < Height() - sizeKernel / 2; y++) {
            int r = 0;
            int g = 0;
            int b = 0;
            // 在“卷积核”3*3区域进行r、g、b累加计算
            for (int i = -sizeKernel / 2; i <= sizeKernel / 2; i++) {
                for (int j = -sizeKernel / 2; j <= sizeKernel / 2; j++) {
                    Pixel &color = At(y + j, x + j);
                    r += color.red * Gx[sizeKernel / 2 + i][sizeKernel / 2 + j];
                    g += color.red * Gy[sizeKernel / 2 + i][sizeKernel / 2 + j];
                }
            }
            r = abs(r);
            g = abs(g);
            int G = sqrt(pow(r, 2) + pow(g, 2));

            // 除以以sumKernel求均值 要求不超过0-255 超了就赋值0/255
            r = qBound(0, G, 255);
            g = qBound(0, G, 255);
            b = qBound(0, G, 255);
            new_im.setPixel(y, x, r, g, b);
        }
    }
    new_im.CopyTo((*this));
    fix(sizeKernel);
}

// 边缘检测
void Image::Canny(int minVale, int maxVale) {
    Gaussian_filter();
    Sobel();
    int h = Height();
    int w = Width();
    Image new_im = Image(h, w);

    // 非极大值抑制
    for (int y = 0; y < h; y++) {
        for (int x = 0; x < w; x++) {
            // 八个方向
            unsigned char A = At(y, x).red;
            unsigned char B = At(y, max(x - 1, 0)).red;
            unsigned char C = At(y, min(x + 1, w - 1)).red;
            unsigned char D = At(max(y - 1, 0), x).red;
            unsigned char E = At(min(y + 1, h - 1), x).red;
            // 右上左下
            unsigned char F = At(min(y + 1, h - 1), min(x + 1, w - 1)).red;
            unsigned char G = At(max(y - 1, 0), max(x - 1, 0)).red;
            // 右下左上
            unsigned char H = At(max(y - 1, 0), min(x + 1, w - 1)).red;
            unsigned char I = At(min(y + 1, h - 1), max(x - 1, 0)).red;
            if (A >= B && A >= C) {
                new_im.setPixel(y, x, At(y, x));
            } else if (A >= E && A >= D) {
                new_im.setPixel(y, x, At(y, x));
            } else if (A >= F && A >= G) {
                new_im.setPixel(y, x, At(y, x));
            } else if (A >= H && A >= I) {
                new_im.setPixel(y, x, At(y, x));
            } else {
                new_im.setPixel(y, x, 0, 0, 0);
            }
        }
    }

    // 优化操作：边缘细化  但我用均值滤波代替 原理相似
    mean_filter();

    int sizeKernel = 9;
    // 双阈值处理
    for (int x = sizeKernel / 2; x < Width() - sizeKernel / 2; x++) {
        for (int y = sizeKernel / 2; y < Height() - sizeKernel / 2; y++) {
            if (new_im.At(y, x).red < minVale) {
                new_im.setPixel(y, x, 0, 0, 0);
            } else if (new_im.At(y, x).red > minVale && new_im.At(y, x).red < maxVale) {
                for (int i = -sizeKernel / 2; i <= sizeKernel / 2; i++) {
                    for (int j = -sizeKernel / 2; j <= sizeKernel / 2; j++) {
                        if (At(min(y + j, h - 1), min(x + i, w - 1)).red == 255) {
                            new_im.setPixel(y, x, 255, 255, 255);
                            break;;
                        }
                    }
                }
            } else {
                new_im.setPixel(y, x, 255, 255, 255);
            }
        }
    }
    new_im.CopyTo((*this));
    fix(sizeKernel);
}

void Image::Mosaic() {
    Image new_im = Image(Height(), Width());
    int Mosize = 8; //将图像分为8*8的小格
    int h = Height();
    int w = Width();
    for (int i = 0; i < h; i += Mosize)
        for (int j = 0; j < w; j += Mosize) {
            unsigned char red = 0, green = 0, blue = 0;
            for (int x = i; x < i + Mosize && x < h; x++) {
                for (int y = j; y < j + Mosize && y < w; y++) {
                    Pixel color = pixel(x, y);
                    red += color.red / 64;       //先相加再求均值会超出unsigned char 的取值范围
                    green += color.gre / 64;
                    blue += color.blu / 64;
                }
            }

            Pixel Newcolor;
            Newcolor.red = red;
            Newcolor.gre = green;
            Newcolor.blu = blue;
            for (int x = i; x < i + Mosize && x < h; x++) {
                for (int y = j; y < j + Mosize && y < w; y++) {
                    new_im.setPixel(x, y, Newcolor);  //在每个小方格内上色
                }
            }
        }
    new_im.CopyTo((*this));
}
